package com.sjc.counter.v2;

import com.sjc.counter.entity.RequestInfo;
import com.sjc.counter.entity.RequestStat;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Classname Aggregator
 * @Description
 * @Date 2020/5/1 16:11
 * @Created by SangJiacun
 */
public class Aggregator {

    public Map<String, RequestStat> aggregate(Map<String, List<RequestInfo>> requestInfos, long durationInMillis) {
        Map<String, RequestStat> requestStats = new HashMap<>();
        for(Map.Entry<String, List<RequestInfo>> entry : requestInfos.entrySet()){
            String apiName = entry.getKey();
            List<RequestInfo> requestInfosPerApi = entry.getValue();

            RequestStat requestStat = doAggregate(requestInfosPerApi, durationInMillis);
            requestStats.put(apiName,requestStat);
        }
        return requestStats;
    }


    private RequestStat doAggregate(List<RequestInfo> requestInfos, long durationInMillis) {
        List<Double> respTimes = new ArrayList<>();
        for(RequestInfo requestInfo : requestInfos){
            double responseTime = requestInfo.getResponseTime();
            respTimes.add(responseTime);
        }

        RequestStat requestStat = new RequestStat();
        requestStat.setMaxResponseTime(max(respTimes));
        requestStat.setMinResponseTime(min(respTimes));
        requestStat.setAvgResponseTime(avg(respTimes));
        requestStat.setP999ResponseTime(percentile999(respTimes));
        requestStat.setP99ResponseTime(percentile99(respTimes));
        requestStat.setCount(respTimes.size());
        requestStat.setTps((long) tps(respTimes.size(), durationInMillis/1000));
        return requestStat;
    }

    private double max(List<Double> dataset){
        return Collections.max(dataset);
    }

    public double min(List<Double> dataset){
        return Collections.min(dataset);
    }

    public double avg(List<Double> dataset){
        return dataset.stream().collect(Collectors.averagingDouble(Double::doubleValue));
    }

    private double tps(int count, double duration) {
        return count / duration;
    }

    private double percentile999(List<Double> dataset) {
        dataset.stream().sorted(Comparator.comparing(Double::doubleValue)).collect(Collectors.toList());
        return dataset.get((int)(dataset.size()*0.999));
    }

    private double percentile99(List<Double> dataset) {
        dataset.stream().sorted(Comparator.comparing(Double::doubleValue)).collect(Collectors.toList());
        return dataset.get((int)(dataset.size()*0.99));
    }

    private double percentile(List<Double> dataset, double ratio) {
        return 0.0;
    }
}
